package com.wmx.yuanyuan.image;

import org.junit.jupiter.api.Test;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.filechooser.FileSystemView;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;

/**
 * Java jdk 原生 ImageIO API 图像压缩工具类
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/1/25 16:09
 */
public class ImageIoCompressUtils {

    /**
     * Java SE 元素 API 压缩图片——亲测能压缩 80%，5.74M 压缩后只有 1.21M.
     *
     * @param sourceInputStream ：被压缩的图片输入流
     * @param destFile          ：压缩文件保存的文件路径，也可以是任意输出流，比如用于文件下载等等。
     * @throws IOException
     */
    public static void compressImage(InputStream sourceInputStream, File destFile) throws IOException {
        ImageWriter imageWriter = null;
        OutputStream outputStream = null;
        ImageOutputStream imageOutputStream = null;
        try {
            //读取文件
            BufferedImage bufferedImage = ImageIO.read(sourceInputStream);

            //返回一个迭代器，该迭代器包含当前注册的所有声称能够对命名格式进行编码的 ImageWriter
            Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName("jpg");
            //ImageWriter 是用于编码和写入图像的抽象超类
            imageWriter = writerIterator.next();

            //获取压缩后的输出流
            outputStream = new FileOutputStream(destFile);

            //将输出流包装为图片输出流，通过它进行输出
            imageOutputStream = ImageIO.createImageOutputStream(outputStream);

            //设置写入的输出流
            imageWriter.setOutput(imageOutputStream);

            // 返回此文件格式的适当类型的新ImageWriteParam对象，该对象包含默认值,即如果未指定ImageWriteParam对象，将使用的值。
            // 这是一个非常有用的起点，可以用来调整几个参数，或者不使用默认设置。
            ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();

            //指定压缩模式
            //压缩模式一共有四种，MODE_EXPLICIT 是其中一种，表示 ImageWriter 可以根据后续的 set 的附加信息进行平铺和压缩，
            //比如说下面的 setCompressionQuality() 方法
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            //将压缩质量设置为介于[0,1]之间的值，值越小压缩越严重，图像质量也越差
            imageWriteParam.setCompressionQuality(0.5f);

            //压缩并输出
            imageWriter.write(null, new IIOImage(bufferedImage, null, null), imageWriteParam);
        } finally {
            if (outputStream != null) {
                outputStream.flush();
                outputStream.close();
            }
            if (imageOutputStream != null) {
                imageOutputStream.flush();
                imageOutputStream.close();
            }
            if (imageWriter != null) {
                imageWriter.dispose();
            }
        }
    }

    @Test
    public void testCompressImage() throws IOException {
        InputStream inputStream = ImageIoCompressUtils.class.getClassLoader().getResourceAsStream("public/images/大美女.jpg");
        File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();

        File file = new File(homeDirectory, System.currentTimeMillis() + ".jpg");
        ImageIoCompressUtils.compressImage(inputStream, file);
        System.out.println("压缩文件：" + file);
    }
}
